/*
 * Copyright 2019, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bignerdranch.travelcommunity.ui

import android.content.Context
import android.content.Intent
import android.util.SparseArray
import android.view.View
import androidx.core.util.forEach
import androidx.core.util.set
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import com.bignerdranch.travelcommunity.R
import com.bignerdranch.travelcommunity.base.BaseViewModel
import com.bignerdranch.tclib.LogUtil
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_home_page.view.*


/**
 * Manages the various graphs needed for a [BottomNavigationView].
 *
 * This sample is a workaround until the Navigation Component supports multiple back stacks.
 */
fun BottomNavigationView.setupWithNavController(
    navGraphIds: List<Int>,
    fragmentManager: FragmentManager,
    containerId: Int,
    intent: Intent
): LiveData<NavController> {

    // Map of tags



    val graphIdToTagMap = SparseArray<String>()
    // Result. Mutable live data with the selected controlled
    val selectedNavController = MutableLiveData<NavController>()

    var firstFragmentGraphId = 0

    // First create a NavHostFragment for each NavGraph ID
    navGraphIds.forEachIndexed { index, navGraphId ->
        val fragmentTag = getFragmentTag(index)
    LogUtil.e("fragmentTag$fragmentTag  ${graphIdToTagMap.size()}  ${fragmentManager.backStackEntryCount}" )

        // Find or create the Navigation host fragment
        val navHostFragment = obtainNavHostFragment(
            fragmentManager,
            fragmentTag,
            navGraphId,
            containerId
        )
  LogUtil.e("nav${navHostFragment.isResumed} $navHostFragment")
        // Obtain its id
        val graphId = navHostFragment.navController.graph.id

        if (index == 0) {
            firstFragmentGraphId = graphId
        }

        // Save to the map
        graphIdToTagMap[graphId] = fragmentTag


        // Attach or detach nav host fragment depending on whether it's the selected item.
        if (this.selectedItemId == graphId) {
            // Update livedata with the selected graph
            selectedNavController.value = navHostFragment.navController
            attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
        } else {
            detachNavHostFragment(fragmentManager, navHostFragment)
        }

        LogUtil.e("我还没死呢 ")
    }

    // Now connect selecting an item with swapping Fragments
    var selectedItemTag = graphIdToTagMap[this.selectedItemId]
    val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
    var isOnFirstFragment = selectedItemTag == firstFragmentTag

    // When a navigation item is selected
    setOnNavigationItemSelectedListener { item ->
        // Don't do anything if the state is state has already been saved.

           if (fragmentManager.isStateSaved) {
               false
           } else {
               val newlySelectedItemTag = graphIdToTagMap[item.itemId]
               if (selectedItemTag != newlySelectedItemTag) {
                   // Pop everything above the first fragment (the "fixed start destination")
                   //
                   fragmentManager.popBackStack(
                       firstFragmentTag,
                       FragmentManager.POP_BACK_STACK_INCLUSIVE
                   )
                   val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
                           as NavHostFragment
                   /*
                * 进行登陆判断
                * */

                   with(selectedFragment.navController) {
                       when (item.itemId) {
                           R.id.mine, R.id.other, R.id.message -> {
                               if (!BaseViewModel.userIsLogin)
                                   navigate(R.id.login_and_register)
                           }


                       }
                   }

                   // Exclude the first fragment tag because it's always in the back stack.
                   //排除第一个fragment，因为他总是存在返回堆栈中
                   if (firstFragmentTag != newlySelectedItemTag) {
                       //提交一个事务，来清空返回堆栈并添加第一个fragment进入返回堆栈中，
                       //以将第一个fragment作为下一次返回的目的地
                       // Commit a transaction that cleans the back stack and adds the first fragment
                       // to it, creating the fixed started destination.
                       fragmentManager.beginTransaction()
                           .setCustomAnimations(
                               R.anim.nav_default_enter_anim,
                               R.anim.nav_default_exit_anim,
                               R.anim.nav_default_pop_enter_anim,
                               R.anim.nav_default_pop_exit_anim
                           )

                           .attach(selectedFragment)
                           .setPrimaryNavigationFragment(selectedFragment)
                           .apply {
                               // Detach all other Fragments
                               graphIdToTagMap.forEach { _, fragmentTagIter ->
                                   if (fragmentTagIter != newlySelectedItemTag) {
                                       detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
                                   }
                               }
                           }
                           .addToBackStack(firstFragmentTag)
                           .setReorderingAllowed(true)
                           .commit()
                   }
                   selectedItemTag = newlySelectedItemTag
                   isOnFirstFragment = selectedItemTag == firstFragmentTag

                   selectedNavController.value = selectedFragment.navController


                   true
               } else {
                   false
               }
           }
       }


    // Optional: on item reselected, pop back stack to the destination of the graph
    setupItemReselected(graphIdToTagMap, fragmentManager)

    // Handle deep link
    setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)

    // Finally, ensure that we update our BottomNavigationView when the back stack changes
    fragmentManager.addOnBackStackChangedListener {
        if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
            this.selectedItemId = firstFragmentGraphId
        }

        // Reset the graph if the currentDestination is not valid (happens when the back
        // stack is popped after using the back button).
        selectedNavController.value?.let { controller ->
            if (controller.currentDestination == null) {
                controller.navigate(controller.graph.id)
            }
        }
    }
    return selectedNavController
}

private fun BottomNavigationView.setupDeepLinks(
    navGraphIds: List<Int>,
    fragmentManager: FragmentManager,
    containerId: Int,
    intent: Intent
) {
    navGraphIds.forEachIndexed { index, navGraphId ->
        val fragmentTag = getFragmentTag(index)

        // Find or create the Navigation host fragment
        val navHostFragment = obtainNavHostFragment(
            fragmentManager,
            fragmentTag,
            navGraphId,
            containerId
        )
        // Handle Intent
        if (navHostFragment.navController.handleDeepLink(intent)
                && selectedItemId != navHostFragment.navController.graph.id) {
            this.selectedItemId = navHostFragment.navController.graph.id
        }
    }
}

private fun BottomNavigationView.setupItemReselected(
    graphIdToTagMap: SparseArray<String>,
    fragmentManager: FragmentManager
) {
    setOnNavigationItemReselectedListener { item ->
        val newlySelectedItemTag = graphIdToTagMap[item.itemId]
        val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
            as NavHostFragment
        val navController = selectedFragment.navController
        // Pop the back stack to the start destination of the current navController graph
        navController.popBackStack(
            navController.graph.startDestination, false
        )
    }
}

private fun detachNavHostFragment(
    fragmentManager: FragmentManager,
    navHostFragment: NavHostFragment
) {
    fragmentManager.beginTransaction()
        .detach(navHostFragment)
        .commitNow()
}

private fun attachNavHostFragment(
    fragmentManager: FragmentManager,
    navHostFragment: NavHostFragment,
    isPrimaryNavFragment: Boolean
) {
    fragmentManager.beginTransaction()
        .attach(navHostFragment)
        .apply {
            if (isPrimaryNavFragment) {
                setPrimaryNavigationFragment(navHostFragment)
            }
        }
        .commitNow()

}

private fun obtainNavHostFragment(
    fragmentManager: FragmentManager,
    fragmentTag: String,
    navGraphId: Int,
    containerId: Int
): NavHostFragment {
    // If the Nav Host fragment exists, return it
    val existingFragment = fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment?
    existingFragment?.let { return it }

    // Otherwise, create it and return it.

    val navHostFragment = NavHostFragment.create(navGraphId)



    fragmentManager.beginTransaction()
        .add(containerId, navHostFragment, fragmentTag)
        .commitNow()
    return navHostFragment
}

private fun FragmentManager.isOnBackStack(backStackName: String): Boolean {
    val backStackCount = backStackEntryCount
    for (index in 0 until backStackCount) {
        if (getBackStackEntryAt(index).name == backStackName) {
            return true
        }
    }
    return false
}

private fun getFragmentTag(index: Int) = "bottomNavigation#$index"

//清空返回栈
fun clearAndToHome(context: Context){
    val intent = Intent(context,HomePageActivity::class.java)
        .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
    context.startActivity(intent)
}
